package de.dnb.basics.filtering;

import de.dnb.basics.applicationComponents.RangeCheckUtils;

/**
 * Filterkriterium geschlossenes Intervall. Verschiedene Intervalle sind über
 * ihre Untergrenze miteinander vergleichbar. Ist die Untergrenze gleich,
 * so kommt das kleinere Intervall vor dem größeren (Vergleich der
 * Obergrenze).
 * 
 * @param <T>                   Typ, der {@link Comparable} implementiert
 * @author Christian Baumann
 * 
 */
public class Between<T extends Object & Comparable<T>> implements
    IPredicate<T>, Comparable<Between<T>> {

    public final T lowerBound;
    public final T higherBound;

    public Between(final T lowerBound, final T higherBound) {
        RangeCheckUtils.assertReferenceParamNotNull("lowerBound", lowerBound);
        RangeCheckUtils.assertReferenceParamNotNull("higherBound", higherBound);

        if (!(lowerBound.compareTo(higherBound) <= 0))
            throw new IllegalArgumentException("lowerBound " + lowerBound
                + " must be <= higherBound " + higherBound);

        this.lowerBound = lowerBound;
        this.higherBound = higherBound;
    }

    @Override
    public final boolean accept(final T object) {
        return lowerBound.compareTo(object) <= 0
            && higherBound.compareTo(object) >= 0;
    }

    @Override
    public final int compareTo(final Between<T> other) {
        int ret = this.lowerBound.compareTo(other.lowerBound);
        if (ret == 0)
            ret = this.higherBound.compareTo(other.higherBound);
        return ret;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result =
            prime * result
                + ((higherBound == null) ? 0 : higherBound.hashCode());
        result =
            prime * result + ((lowerBound == null) ? 0 : lowerBound.hashCode());
        return result;
    }

    @Override
    public String toString() {
        return "<" + lowerBound + " .. " + higherBound + ">";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Between other = (Between) obj;
        if (higherBound == null) {
            if (other.higherBound != null)
                return false;
        } else if (!higherBound.equals(other.higherBound))
            return false;
        if (lowerBound == null) {
            if (other.lowerBound != null)
                return false;
        } else if (!lowerBound.equals(other.lowerBound))
            return false;
        return true;
    }

    public static void main(String[] args) {
        Between<String> between1 = new Between<String>("2", "2");
        Between<String> between2 = new Between<String>("1", "2");
        System.out.println(between1.equals(between2));
        System.out.println(between1.compareTo(between2));
    }

}
